package com.douyin.controller;

import cn.hutool.core.util.StrUtil;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.douyin.dto.Result;
import com.douyin.dto.VideoDTO;
import com.douyin.entity.Videos;
import com.douyin.properties.JwtProperties;
import com.douyin.service.RecommendationService;
import com.douyin.service.VideosService;
import com.douyin.utils.JwtUtil;
import com.douyin.utils.RedisConstants;
import com.douyin.vo.VideoVO;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;
import com.alibaba.fastjson.JSON;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;

@Slf4j // 日志注解，用于打印日志
@RestController // 标识该类为REST风格的控制器，返回JSON数据
@RequestMapping("/videos") // 基础请求路径，所有接口都以/videos开头
public class VideosController {

    @Resource // 注入视频服务层对象，用于调用业务逻辑
    private VideosService videosService;

    @Resource // 注入阿里云OSS客户端，用于处理文件上传相关操作
    private OSS ossClient;

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private RecommendationService recommendationService;

    @Autowired // 注入JWT配置属性，包含密钥等信息
    private JwtProperties jwtProperties;

    @Value("${aliyun.oss.bucket-name}") // 从配置文件注入OSS存储桶名称
    private String bucketName;

    @Value("${aliyun.oss.domain}") // 从配置文件注入OSS域名
    private String domain;

    @Value("${aliyun.oss.access-key-id}") // 从配置文件注入阿里云访问密钥ID
    private String accessKeyId;


    /**
     * 直接上传视频文件到OSS并返回URL
     * 适用于需要后端中转上传的场景（而非前端直传）
     */
    @PostMapping("/upload/file")
    public Result uploadVideoFile(@RequestParam("file") MultipartFile videoFile) {
        // 校验文件是否为空
        if (videoFile.isEmpty()) {
            return Result.fail("上传文件不能为空");
        }

        try {
            // 校验文件大小（限制100MB以内，与签名上传保持一致）
            long fileSize = videoFile.getSize();
            if (fileSize > 1024 * 1024 * 100) {
                return Result.fail("文件大小不能超过100MB");
            }

            // 生成唯一文件名（UUID + 原文件后缀）
            String originalFilename = videoFile.getOriginalFilename();
            String suffix = StrUtil.subAfter(originalFilename, ".", true); // 获取文件后缀
            String fileName = UUID.randomUUID().toString() + "." + suffix;

            // 构建OSS中的存储路径（与签名上传保持一致的目录结构）
            String key = "videos/" + UUID.randomUUID() + "/" + fileName;

            // 上传文件到OSS
            ossClient.putObject(bucketName, key, videoFile.getInputStream());

            // 生成文件访问URL
            String videoUrl = "https://" + bucketName + "." + domain + "/" + key;

            return Result.ok(videoUrl); // 直接返回视频URL
        } catch (Exception e) {
            log.error("视频文件上传失败", e);
            return Result.fail("视频上传失败");
        }
    }
    /**
     * 发布视频
     * 前端上传视频到OSS后，调用此接口保存视频信息到数据库
     */
    @PostMapping
    public Result publishVideo(@RequestBody VideoDTO videoDTO, @RequestHeader("Authorization") String token) {
        // 校验token是否为空
        if (StrUtil.isBlank(token)) {
            return Result.fail("未登录，请先登录");
        }

        // 从token中解析用户ID
        try {
            // 移除Bearer前缀（如果有的话，标准JWT格式可能带此前缀）
            if (token.startsWith("Bearer ")) {
                token = token.substring(7);
            }

            // 解析JWT获取claims（包含用户信息等数据）
            Claims claims = JwtUtil.parseJWT(jwtProperties.getUserSecretKey(), token);
            if (claims == null) {
                return Result.fail("无效的token");
            }

            // 检查token是否在黑名单中（已登出的token）
            String blacklistedKey = RedisConstants.BLACKLIST_TOKEN_KEY + token;
            if (Boolean.TRUE.equals(redisTemplate.hasKey(blacklistedKey))) {
                return Result.fail("token已失效，请重新登录");
            }

            // 从claims中获取用户ID
            Long userId = claims.get("userId", Long.class);
            if (userId == null) {
                return Result.fail("无效的token");
            }

            // 构建视频实体对象
            Videos video = new Videos();
            video.setUserId(userId) // 设置发布者ID
                    .setTitle(videoDTO.getTitle()) // 设置视频标题
                    .setDescription(videoDTO.getDescription()) // 设置视频描述
                    .setVideoUrl(videoDTO.getVideoUrl()) // 设置视频在OSS的地址（前端上传后获取）
                    .setCoverUrl(videoDTO.getCoverUrl()) // 设置封面图在OSS的地址
                    .setPlayCount(0L) // 初始播放量为0
                    .setLikeCount(0L) // 初始点赞数为0
                    .setCommentCount(0L) // 初始评论数为0
                    .setShareCount(0L) // 初始分享数为0
                    .setCreatedAt(LocalDateTime.now()) // 设置创建时间为当前时间
                    .setUpdatedAt(LocalDateTime.now()) // 设置更新时间为当前时间
                    .setStatus(1); // 设置状态为1（假设1表示正常）

            // 保存视频信息到数据库
            boolean saved = videosService.save(video);
            if (saved) {
                // 清除推荐视频缓存（因为有新视频发布，推荐列表可能变化）
                redisTemplate.delete(RedisConstants.VIDEO_RECOMMEND_KEY);
                return Result.ok(video.getId()); // 返回成功，携带视频ID
            }
            return Result.fail("发布视频失败");

        } catch (Exception e) {
            log.error("解析token失败", e); // 打印token解析错误日志
            return Result.fail("token解析失败，请重新登录");
        }
    }

    /**
     * 分页获取推荐视频
     * 从缓存或数据库中获取推荐视频列表，按分页参数返回
     */
// VideosController 中修改
    @GetMapping("/recommend")
    public Result recommendVideos(@RequestParam(defaultValue = "1") Integer pageNum,
                                  @RequestParam(defaultValue = "10") Integer pageSize) {
        // 直接调用热门推荐（若需个性化，可传入当前用户ID）
        return Result.ok(recommendationService.getHotRecommend(pageNum, pageSize));
    }


    @GetMapping("/share/{videoId}")
    public Result shareVideos(@PathVariable Long videoId) {
        log.info("shareVideos:{}",videoId);
        return videosService.shareVideos(videoId);
    }
    /**
     * 获取视频详情
     * 根据视频ID查询视频详细信息，并增加播放量
     */
    @GetMapping("/{id}")
    public Result getVideoDetail(@PathVariable Long id) {
        // 增加视频播放量（每次查看详情都计数）
        videosService.incrementPlayCount(id);

        // 查询视频详情
        VideoVO videoVO = videosService.getVideoDetail(id);
        // 视频存在则返回详情，否则返回不存在提示
        return videoVO != null ? Result.ok(videoVO) : Result.fail("视频不存在");
    }

    /**
     * 分页获取用户发布的视频
     * 根据用户ID查询其发布的所有视频，支持分页
     */
    @GetMapping("/user/{userId}")
    public Result getUserVideos(@PathVariable Long userId,
                                @RequestParam(defaultValue = "1") Integer pageNum,
                                @RequestParam(defaultValue = "10") Integer pageSize) {
        Page<Videos> page = new Page<>(pageNum, pageSize); // 创建分页对象
        // 调用服务层查询指定用户的视频
        IPage<VideoVO> videoPage = videosService.queryUserVideos(page, userId);
        return Result.ok(videoPage); // 返回分页结果
    }
    /**
     * 搜索视频接口
     * @param keyword 搜索关键词
     * @param pageNum 页码（默认1）
     * @param pageSize 每页数量（默认10）
     * @param sortBy 排序字段（createTime/playCount/likeCount，默认createTime）
     * @return 分页的视频列表
     */
    @GetMapping("/search")
    public Result searchVideos(
            @RequestParam String keyword,
            @RequestParam(defaultValue = "1") Integer pageNum,
            @RequestParam(defaultValue = "10") Integer pageSize,
            @RequestParam(defaultValue = "createTime") String sortBy) {

        // 校验排序字段合法性
        if (!Arrays.asList("createTime", "playCount", "likeCount").contains(sortBy)) {
            sortBy = "createTime"; // 非法字段默认按创建时间排序
        }

        IPage<VideoVO> videoPage = videosService.searchVideos(keyword, pageNum, pageSize, sortBy);
        return Result.ok(videoPage);
    }
}

